x86: further adjustments to arch_set_info_guest() after c/s 23142:f5e8d152a565
authorJan Beulich <jbeulich@novell.com>
Tue, 17 May 2011 12:55:45 +0000 (13:55 +0100)
committerJan Beulich <jbeulich@novell.com>
Tue, 17 May 2011 12:55:45 +0000 (13:55 +0100)
The adjustments to v->arch.user_regs.eflags and the initialization of
the int80 direct trap must be done earlier (namely before the function
may bail because of inconsistencies between input and stored state on
an already initialised vCPU) so that stored state is consistent, and
for arch_get_info_guest() to not have its eflags related BUG_ON()
triggered.

Further, v->arch.pv_vcpu.ctrlreg[] indices 3 and 1 aren't being kept
up to date while the domain is running, so consistency checks must
instead be done against v->arch.guest_table{,_user}.

Additionally, for 64-bit pv domains, CR1 must also be checked to be
consistent with the kernel mode setting for the vCPU, and the whole
CR1 checking should not be done for 32-bit pv domains.

Signed-off-by: Jan Beulich <jbeulich@novell.com>
xen/arch/x86/domain.c

index 8bb0f5dd81cca4e22cd8ab7adb12437dc5c873f1..f5f6fcfe2a46058de78ad2392f70efcf5dff4b34 100644 (file)
@@ -843,6 +843,15 @@ int arch_set_info_guest(
         goto out;
     }
 
+    init_int80_direct_trap(v);
+
+    /* IOPL privileges are virtualised. */
+    v->arch.pv_vcpu.iopl = (v->arch.user_regs.eflags >> 12) & 3;
+    v->arch.user_regs.eflags &= ~X86_EFLAGS_IOPL;
+
+    /* Ensure real hardware interrupts are enabled. */
+    v->arch.user_regs.eflags |= X86_EFLAGS_IF;
+
     if ( !v->is_initialised )
     {
         v->arch.pv_vcpu.ldt_base = c(ldt_base);
@@ -850,11 +859,27 @@ int arch_set_info_guest(
     }
     else
     {
-        bool_t fail = v->arch.pv_vcpu.ctrlreg[3] != c(ctrlreg[3]);
+        unsigned long pfn = pagetable_get_pfn(v->arch.guest_table);
+        bool_t fail;
 
+        if ( !compat )
+        {
+            fail = xen_pfn_to_cr3(pfn) != c.nat->ctrlreg[3];
 #ifdef CONFIG_X86_64
-        fail |= v->arch.pv_vcpu.ctrlreg[1] != c(ctrlreg[1]);
+            if ( pagetable_is_null(v->arch.guest_table_user) )
+                fail |= c.nat->ctrlreg[1] || !(flags & VGCF_in_kernel);
+            else
+            {
+                pfn = pagetable_get_pfn(v->arch.guest_table_user);
+                fail |= xen_pfn_to_cr3(pfn) != c.nat->ctrlreg[1];
+            }
+        } else {
+            l4_pgentry_t *l4tab = __va(pfn_to_paddr(pfn));
+
+            pfn = l4e_get_pfn(*l4tab);
+            fail = compat_pfn_to_cr3(pfn) != c.cmp->ctrlreg[3];
 #endif
+        }
 
         for ( i = 0; i < ARRAY_SIZE(v->arch.pv_vcpu.gdt_frames); ++i )
             fail |= v->arch.pv_vcpu.gdt_frames[i] != c(gdt_frames[i]);
@@ -894,15 +919,6 @@ int arch_set_info_guest(
     v->arch.pv_vcpu.ctrlreg[0] &= X86_CR0_TS;
     v->arch.pv_vcpu.ctrlreg[0] |= read_cr0() & ~X86_CR0_TS;
 
-    init_int80_direct_trap(v);
-
-    /* IOPL privileges are virtualised. */
-    v->arch.pv_vcpu.iopl = (v->arch.user_regs.eflags >> 12) & 3;
-    v->arch.user_regs.eflags &= ~X86_EFLAGS_IOPL;
-
-    /* Ensure real hardware interrupts are enabled. */
-    v->arch.user_regs.eflags |= X86_EFLAGS_IF;
-
     cr4 = v->arch.pv_vcpu.ctrlreg[4];
     v->arch.pv_vcpu.ctrlreg[4] = cr4 ? pv_guest_cr4_fixup(v, cr4) :
         real_cr4_to_pv_guest_cr4(mmu_cr4_features);